package com.cosmocoder.persistence.hibernate;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.cosmocoder.persistence.Dao;

public class HibernateDao<EntityType, IdType extends Serializable> extends HibernateDaoSupport implements Dao<EntityType, IdType>{
	
	Class<?> entityClass = null;
	
	@SuppressWarnings("unchecked")
	public Class<?> getEntityClass() {
		if(entityClass == null) {
			entityClass = (Class<EntityType>) (
					(ParameterizedType) getClass()
						.getGenericSuperclass()
					).getActualTypeArguments()[0];
		}
		return entityClass;
	}
	
	void setEntityClass (Class<?> entityClass) {
		//((ParameterizedType) getClass()..getGenericSuperclass()).getActualTypeArguments()[0] = entityClass;
		this.entityClass = entityClass;
	}
	
	@SuppressWarnings("unchecked")
	public EntityType get (IdType id) {
		return (EntityType) getHibernateTemplate().get(getEntityClass(), id);
	}
	
	
	public Collection<EntityType> getAll () {
		return getByCriteria();
	}
	
	public EntityType makePersistent(EntityType entity) {
		getHibernateTemplate().saveOrUpdate(entity);
		return entity;
	}

	public EntityType makeTransient(EntityType entity) {
		getHibernateTemplate().delete(entity);
		return entity;
	}
	
    @SuppressWarnings("unchecked")
    public Collection<EntityType> getByCriteria(Criterion... criterions) {
        Criteria criteria = getSession().createCriteria(getEntityClass());
        for (Criterion criterion : criterions) {
        	criteria.add(criterion);
        }
        return criteria.list();
   }

	public void clear() {
		getHibernateTemplate().clear();
	}

	public void flush() {
		getHibernateTemplate().flush();
	}

	public Collection<EntityType> getByProperty(String property, Object value) {
		return getByCriteria(Restrictions.eq(property, value));
	}

	public Collection<EntityType> getByProperties(Map<String, Object> propetiesMap) {
		Criterion[] criterions = new Criterion[propetiesMap.size()];
		int currentCriterionIndex = 0;
		for(Map.Entry<String, Object> propertyEntry : propetiesMap.entrySet()) {
			criterions[currentCriterionIndex] = Restrictions.eq(propertyEntry.getKey(), propertyEntry.getValue());
			currentCriterionIndex ++;
		}
		
		return getByCriteria(criterions);
		
	}
}
